﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CpuUsageAPI;
using System.Xml;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace ProcessManager
{
    /// <summary>
    /// 进程管理代理类
    /// </summary>
    public class ProcessProvider
    {
        /// <summary>
        /// 所有进程信息泛型集合
        /// </summary>
        private Dictionary<int, ProcessData> allPdDict = new Dictionary<int, ProcessData>();
        private const ProcessData PROCESS_DATA_NOT_FOUND = null;
        public List<ProcessInfo> ProInfoList = new List<ProcessInfo>();

        /// <summary>
        /// Cpu总利用率
        /// </summary>
        public int TotalCpuUsage = 0;
        /// <summary>
        /// Cpu占用率极限值
        /// </summary>
        public int LimitCpuUsage = 40;
        /// <summary>
        /// 内存极限使用率
        /// </summary>
        public int LimitMemSize = 50000;
        /// <summary>
        /// Cpu或内存使用无变化次数
        /// </summary>
        public int FixedTimes = 10;

        public ProcessProvider()
        {

        }

        public void ConfigProcesses()
        {
            if (!File.Exists(Application.StartupPath + "\\ProcessesConfig.xml"))
            {
                throw new Exception("配置文件损坏，无法正常配置程序");
            }

            ProInfoList.Clear();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(Application.StartupPath + "\\ProcessesConfig.xml");
            XmlNode rootNode = xmlDoc.SelectSingleNode("Root");

            #region 读取全局参数

            XmlNode gNode = rootNode.SelectSingleNode("GlobalConfig");
            if (gNode != null)
            {
                XmlNode no = gNode.SelectSingleNode("LimitCpuUsage");
                if (no != null)
                {
                    LimitCpuUsage = Convert.ToInt32(no.InnerText);
                }

                no = gNode.SelectSingleNode("LimitMemSize");
                if (no != null)
                {
                    LimitMemSize = Convert.ToInt32(no.InnerText);
                }

                no = gNode.SelectSingleNode("FixedTimes");
                if (no != null)
                {
                    FixedTimes = Convert.ToInt32(no.InnerText);
                }
            }

            #endregion

            XmlNode prosNode = rootNode.SelectSingleNode("Processes");
            XmlNodeList proNodes = prosNode.SelectNodes("ProcessInfo");
            foreach (XmlNode node in proNodes)
            {
                string fPath = node.SelectSingleNode("FilePath").InnerText;

                ProcessInfo pi = new ProcessInfo();
                pi.FilePath = fPath;
                pi.PlugConfig = new ConfigBuilder.ConfigBuilder();
                //pi.PlugConfig.AccountServiceUri = new Uri("");
                pi.PlugConfig.MachineGuid = new Guid();
                pi.PlugConfig.MissionPath = pi.FilePath;
                pi.PlugConfig.MissionToken = "";
                pi.PlugConfig.TemplatePath = "";

                ProInfoList.Add(pi);
            }
        }

        #region [ Private Methods ]

        private ProcessData ProcessExists(uint ID)
        {
            foreach (ProcessData data in allPdDict.Values)
            {
                if (data.ID == ID)
                {
                    return data;
                }
            }
            return null;
        }

        private bool ProcessUpdated(uint ID)
        {
            foreach (uint num in allPdDict.Keys)
            {
                if (num == ID)
                {
                    return true;
                }
            }
            return false;
        }

        private void GetUsage()
        {
            ProcessEntry32 processInfo = new ProcessEntry32();
            ProcessTimes times = new ProcessTimes();
            IntPtr processHandle = ProcessCPU.PROCESS_HANDLE_ERROR;
            TotalCpuUsage = 0;//Total CPU Usage
            IntPtr handle = ProcessCPU.CreateToolhelp32Snapshot(2, 0);
            if (handle != ProcessCPU.PROCESS_LIST_ERROR)
            {
                processInfo.Size = 0x128;
                bool flag = ProcessCPU.Process32First(handle, ref processInfo);
                while (flag)
                {
                    try
                    {
                        processHandle = ProcessCPU.OpenProcess(0x1f0fff, false, processInfo.ID);
                        ProcessCPU.GetProcessTimes(processHandle, out times.RawCreationTime, out times.RawExitTime
                            , out times.RawKernelTime, out times.RawUserTime);
                        times.ConvertTime();
                        ProcessData data = this.ProcessExists(processInfo.ID);
                        if (data == null)
                        {
                            allPdDict.Add(Convert.ToInt32(processInfo.ID), new ProcessData(processInfo.ID, processInfo.ExeFilename
                                , times.UserTime.Ticks, times.KernelTime.Ticks));
                        }
                        else
                        {
                            TotalCpuUsage += data.UpdateCpuUsage(times.UserTime.Ticks, times.KernelTime.Ticks);
                        }
                    }
                    finally
                    {
                        if (processHandle != ProcessCPU.PROCESS_HANDLE_ERROR)
                        {
                            ProcessCPU.CloseHandle(processHandle);
                        }
                        flag = ProcessCPU.Process32Next(handle, ref processInfo);
                    }
                }
                ProcessCPU.CloseHandle(handle);
            }
        }

        #endregion

        public void UpdateAllProcessCpuUsage()
        {
            this.GetUsage();
            foreach (var p in allPdDict)
            {
                int index = ProInfoList.FindIndex(s => s.ProId == p.Value.CurProcess.Id);

                //进程ID匹配时
                if (index > -1)
                {
                    //检查Cpu占用率是否和上次相同
                    if (ProInfoList[index].CpuUsage == p.Value.CpuUsage)
                    {
                        ProInfoList[index].CpuUsageFixedTimes++;
                    }
                    else
                    {
                        ProInfoList[index].CpuUsageFixedTimes = 0;
                    }
                    //内存占用是否和上次相同
                    if (ProInfoList[index].PhysicalMemSize == p.Value.PhyMemSize)
                    {
                        ProInfoList[index].MemSizeFixedTimes++;
                    }
                    else
                    {
                        ProInfoList[index].MemSizeFixedTimes = 0;
                    }

                    ProInfoList[index].CpuUsage = p.Value.CpuUsage;
                    ProInfoList[index].LogicalMemSize = p.Value.LogicMemSize;
                    ProInfoList[index].PhysicalMemSize = p.Value.PhyMemSize;
                }
            }
        }

        /// <summary>
        /// 关闭程序
        /// 避免同一路径下的外挂开多个，会关闭所有相同路径下的进程
        /// </summary>
        /// <param name="pi"></param>
        public void ShutProcess(ProcessInfo pi)
        {
            foreach (var p in allPdDict.Values)
            {
                try
                {
                    if (p.CurProcess.MainModule.FileName == pi.FilePath)
                    {
                        Process tp = Process.GetProcessById(p.CurProcess.Id);
                        tp.Kill();
                    }
                }
                catch { }
            }
        }
    }
}
